#ifndef __NETWORKPARAM_H__
#define __NETWORKPARAM_H__
namespace SPlayer
{
    namespace Network
    {
        using namespace System;
        using namespace System::Net;
        using namespace System::Net::Sockets;
        using namespace System::Collections::Concurrent;
        using namespace System::Collections::Generic;
        ref class NetworkParamValue :IComparable<String ^>
        {
        public:
            NetworkParamValue(String ^value) : val(value)
            { }
            NetworkParamValue(int value) : val(String::Format("{0}", value))
            { }
            operator String ^ ()
            {
                return val;
            }
            operator int()
            {
                int i = 0;
                Int32::TryParse(val, i);
                return i;
            }
            virtual int CompareTo(String ^ other)
                = IComparable<String ^>::CompareTo
            {
                return val->CompareTo(other);
            }
        private:
            String ^val;
        };
        ref class NetworkParam
        {
        public:
            NetworkParam(String ^name, NetworkParamValue ^value) : name(name), val(value)
            { }
        public:
            operator int()
            {
                return val;
            }
            operator String ^ ()
            {
                return val;
            }
        public:
            String ^name;
            NetworkParamValue ^val;
        };
        ref class NetworkParamCollection
        {
        public:
            static String ^paramSeparator = "&";
            static String ^nameValueSeparator = ":";
        public:
            void add(String ^name, String ^val)
            {
                dictionary->TryAdd(name->ToLower(), gcnew NetworkParamValue(val));
            }
            void add(String ^name, int val)
            {
                dictionary->TryAdd(name->ToLower(), gcnew NetworkParamValue(val));
            }
            void add(String ^name, NetworkParamValue ^val)
            {
                dictionary->TryAdd(name->ToLower(), val);
            }
            void add(NetworkParam ^param)
            {
                dictionary->TryAdd(param->name->ToLower(), param->val);
            }
            void add(NetworkParamCollection ^params)
            {
                for each (auto param in params->dictionary)
                {
                    dictionary->TryAdd(param.Key, param.Value);
                }
            }
            bool existKey(String ^key)
            {
                return dictionary->ContainsKey(key->ToLower());
            }
            property NetworkParamValue ^default[String ^]
            {
                NetworkParamValue ^get(String ^name)
                {
                    return dictionary->default[name->ToLower()];
                }
                void set(String ^name, NetworkParamValue ^val)
                {
                    name = name->ToLower();
                    if (dictionary->ContainsKey(name))
                    {
                        dictionary->default[name] = val;
                    }
                    else
                    {
                        dictionary->TryAdd(name, val);
                    }
                }
            }


        public:
            static NetworkParamCollection ^fromString(String ^paramString)
            {
                auto params = gcnew NetworkParamCollection;
                auto paramStrings = paramString->Split(paramSeparator->ToCharArray());
                for each (auto paramstr in paramStrings)
                {
                    auto devide = paramstr->Split(nameValueSeparator->ToCharArray());
                    auto name = System::Text::Encoding::UTF8->GetString(Convert::FromBase64String(devide[0]));
                    auto value = System::Text::Encoding::UTF8->GetString(Convert::FromBase64String(devide[1]));
                    params->add(name, value);
                }
                return params;
            }
            String ^toString()
            {
                return ToString();
            }
            virtual String ^ToString() override
            {
                // format param into string
                // format : base64name:base64value
                String ^paramString = gcnew String("");
                for each (auto p in dictionary)
                {
                    auto b64name = Convert::ToBase64String(System::Text::Encoding::UTF8->GetBytes(p.Key));
                    auto b64val = Convert::ToBase64String(System::Text::Encoding::UTF8->GetBytes(p.Value));
                    paramString += b64name + nameValueSeparator + b64val + paramSeparator;
                }
                return paramString->Substring(0, paramString->Length - 1);
            }
        private:
            ConcurrentDictionary < String ^, NetworkParamValue ^ > ^dictionary = gcnew ConcurrentDictionary < String ^, NetworkParamValue ^ >;
        };

        inline NetworkParamCollection ^ operator += (NetworkParamCollection ^c, NetworkParam ^param)
        {
            c->add(param->name, param->val);
            return c;
        }

    }
}

#endif // __NETWORKPARAM_H__